package edu.northwestern.cbits.purple_robot_manager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.data.FreezableUtils;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataItem;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityCheck;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityManager;
import edu.northwestern.cbits.purple_robot_manager.probes.builtin.ContinuousProbe;
import edu.northwestern.cbits.purple_robot_manager.probes.devices.AndroidWearProbe;
import edu.northwestern.cbits.purple_robot_manager.probes.devices.wear.WearBatteryProbe;
public class AndroidWearService extends WearableListenerService
{
private static final String PATH_REQUEST_DATA = "/purple-robot/request-data";
private static final String PATH_SEND_CONFIG = "/purple-robot/send-config";
private static final String URI_CRASH_REPORT = "/purple-robot-crash";
private static GoogleApiClient _apiClient = null;
private static void initClient(final Context context)
{
if (AndroidWearService._apiClient == null)
{
Runnable r = new Runnable()
{
public void run()
{
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(context);
builder.addApi(Wearable.API);
AndroidWearService._apiClient = builder.build();
ConnectionResult connectionResult = AndroidWearService._apiClient.blockingConnect(30, TimeUnit.SECONDS);
if (!connectionResult.isSuccess())
{
// Log.e("PR", "Failed to connect to GoogleApiClient.");
}
else
AndroidWearService.requestDataFromDevices(context);
}
};
Thread t = new Thread(r);
t.start();
}
}
public static void requestDataFromDevices(final Context context)
{
Runnable r = new Runnable()
{
public void run()
{
if (AndroidWearService._apiClient == null)
AndroidWearService.initClient(context);
if (AndroidWearService._apiClient != null && AndroidWearService._apiClient.isConnected())
{
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(AndroidWearService._apiClient).await();
byte[] config = AndroidWearService.byteConfig(context);
for (Node node : nodes.getNodes())
{
PendingResult<MessageApi.SendMessageResult> result = Wearable.MessageApi.sendMessage(AndroidWearService._apiClient, node.getId(), PATH_SEND_CONFIG, config);
result.setResultCallback(new ResultCallback<MessageApi.SendMessageResult>()
{
@Override
public void onResult(MessageApi.SendMessageResult sendMessageResult)
{
if (!sendMessageResult.getStatus().isSuccess())
{
// Log.e("PR", "Failed to send message (CONFIG) with status code: " + sendMessageResult.getStatus().getStatusCode());
}
}
});
result = Wearable.MessageApi.sendMessage(AndroidWearService._apiClient, node.getId(), PATH_REQUEST_DATA, new byte[0]);
result.setResultCallback(new ResultCallback<MessageApi.SendMessageResult>()
{
@Override
public void onResult(MessageApi.SendMessageResult sendMessageResult)
{
if (!sendMessageResult.getStatus().isSuccess())
{
// Log.e("PR", "Failed to send message (DATA REQUEST) with status code: " + sendMessageResult.getStatus().getStatusCode());
}
}
});
}
}
}
};
Thread t = new Thread(r);
t.start();
}
private static byte[] byteConfig(Context context)
{
byte[] config = new byte[12];
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (prefs.getBoolean(AndroidWearProbe.ACCELEROMETER_ENABLED, AndroidWearProbe.ACCELEROMETER_DEFAULT_ENABLED))
config[0] = 0x01;
else
config[0] = 0x00;
config[1] = Byte.parseByte(prefs.getString(AndroidWearProbe.ACCELEROMETER_FREQUENCY, ContinuousProbe.DEFAULT_FREQUENCY));
if (prefs.getBoolean(AndroidWearProbe.GYROSCOPE_ENABLED, AndroidWearProbe.GYROSCOPE_DEFAULT_ENABLED))
config[2] = 0x01;
else
config[2] = 0x00;
config[3] = Byte.parseByte(prefs.getString(AndroidWearProbe.GYROSCOPE_FREQUENCY, ContinuousProbe.DEFAULT_FREQUENCY));
if (prefs.getBoolean(AndroidWearProbe.MAGNETOMETER_ENABLED, AndroidWearProbe.MAGNETOMETER_DEFAULT_ENABLED))
config[4] = 0x01;
else
config[4] = 0x00;
config[5] = Byte.parseByte(prefs.getString(AndroidWearProbe.MAGNETOMETER_FREQUENCY, ContinuousProbe.DEFAULT_FREQUENCY));
if (prefs.getBoolean(AndroidWearProbe.LIGHT_METER_ENABLED, AndroidWearProbe.LIGHT_METER_DEFAULT_ENABLED))
config[6] = 0x01;
else
config[6] = 0x00;
config[7] = Byte.parseByte(prefs.getString(AndroidWearProbe.LIGHT_METER_FREQUENCY, ContinuousProbe.DEFAULT_FREQUENCY));
if (prefs.getBoolean(AndroidWearProbe.HEART_METER_ENABLED, AndroidWearProbe.HEART_METER_DEFAULT_ENABLED))
config[8] = 0x01;
else
config[8] = 0x00;
config[9] = Byte.parseByte(prefs.getString(AndroidWearProbe.HEART_METER_FREQUENCY, ContinuousProbe.DEFAULT_FREQUENCY));
if (prefs.getBoolean(AndroidWearProbe.LIVEWELL_COUNTS_ENABLED, AndroidWearProbe.LIVEWELL_COUNTS_DEFAULT_ENABLED))
config[10] = 0x01;
else
config[10] = 0x00;
config[11] = Byte.parseByte(prefs.getString(AndroidWearProbe.LIVEWELL_BIN_SIZE, AndroidWearProbe.LIVEWELL_DEFAULT_BIN_SIZE));
return config;
}
public void onDataChanged(DataEventBuffer buffer)
{
if (AndroidWearService._apiClient.isConnected())
{
final List<DataEvent> events = FreezableUtils.freezeIterable(buffer);
final AndroidWearService me = this;
Runnable r = new Runnable()
{
public void run()
{
long sleepInterval = 2000 / events.size();
for (DataEvent event : events)
{
if (event.getType() == DataEvent.TYPE_CHANGED)
{
DataItem item = event.getDataItem();
if (item.getUri().getPath().startsWith(AndroidWearProbe.URI_READING_PREFIX))
{
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
Bundle data = dataMap.toBundle();
UUID uuid = UUID.randomUUID();
data.putString("GUID", uuid.toString());
LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(me);
Intent intent = new Intent(edu.northwestern.cbits.purple_robot_manager.probes.Probe.PROBE_READING);
intent.putExtras(data);
localManager.sendBroadcast(intent);
String probeName = dataMap.getString("PROBE", "");
if (probeName.equals(WearBatteryProbe.NAME))
{
SanityManager sanity = SanityManager.getInstance(me);
String name = me.getString(R.string.name_sanity_wear_battery);
int level = dataMap.getInt("BATTERY_LEVEL", Integer.MAX_VALUE);
if (level < 30)
{
String message = me.getString(R.string.name_sanity_wear_battery_warning);
sanity.addAlert(SanityCheck.WARNING, name, message, null);
} else
sanity.clearAlert(name);
}
Wearable.DataApi.deleteDataItems(AndroidWearService._apiClient, item.getUri());
}
else if (item.getUri().getPath().startsWith(AndroidWearService.URI_CRASH_REPORT))
{
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
HashMap<String, Object> payload = new HashMap<>();
for (String key : dataMap.keySet())
{
payload.put(key, dataMap.getString(key));
}
LogManager.getInstance(me).log("android_wear_crash", payload);
Wearable.DataApi.deleteDataItems(AndroidWearService._apiClient, item.getUri());
}
try
{
Thread.sleep(sleepInterval);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
else if (event.getType() == DataEvent.TYPE_DELETED)
{
}
}
}
};
Thread t = new Thread(r);
t.start();
}
}
}